package com.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shortlink.admin.dao.entity.UserDO;
import com.shortlink.admin.dao.mapper.UserMapper;
import com.shortlink.admin.dto.req.group.GroupInsertReqDTO;
import com.shortlink.admin.dto.req.user.UserRegisterReqDTO;
import com.shortlink.admin.dto.req.user.UserUpdateReqDTO;
import com.shortlink.admin.dto.resp.user.UserRespDTO;
import com.shortlink.admin.service.GroupService;
import com.shortlink.admin.service.UserService;
import com.shortlink.common.exception.ClientException;
import com.shortlink.common.exception.ServiceException;
import com.shortlink.common.user.UserContext;
import com.shortlink.common.user.UserInfoDTO;
import com.shortlink.common.util.RBloomFilterUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.shortlink.common.constant.RedisKeyConstant.*;

/**
 * 用户接口实现层
 *
 * @author wp
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {
    private final RedissonClient redissonClient;
    private final GroupService groupService;
    private final RBloomFilterUtils bloomFilterUtils;

    @Override
    public UserRespDTO getUserByUsername(String username) {
        if (ObjectUtil.isEmpty(username)) {
            log.info(String.format("username(%s) 不能为空", username));
            throw new ClientException("参数错误");
        }
        RBloomFilter<Object> usernameBloomFilter = bloomFilterUtils.create(USERNAME_BLOOM_KEY);
        if (!usernameBloomFilter.contains(username)) {
            throw new ClientException("用户名不存在");
        }
        UserDO user = lambdaQuery()
                .eq(UserDO::getUsername, username)
                .eq(UserDO::getDelFlag, UserDO.DEL_FLAG_FAIL)
                .one();
        if (user == null) {
            throw new ClientException("用户名不存在");
        }
        UserRespDTO userRespDTO = new UserRespDTO();
        BeanUtils.copyProperties(user, userRespDTO);
        return userRespDTO;
    }

    @Override
    public Boolean hasUsername(String username) {
        if (ObjectUtil.isEmpty(username)) {
            log.info(String.format("username(%s) 不能为空", username));
            throw new ClientException("参数错误");
        }

        RBloomFilter<Object> usernameBloomFilter = bloomFilterUtils.create(USERNAME_BLOOM_KEY);
        if (!usernameBloomFilter.contains(username)) {
            return false;
        }
        return lambdaQuery()
                .eq(UserDO::getUsername, username)
                .eq(UserDO::getDelFlag, UserDO.DEL_FLAG_FAIL)
                .exists();
    }

    @Transactional
    @Override
    public void register(UserRegisterReqDTO userRegisterReqDTO) {
        String username = userRegisterReqDTO.getUsername();
        String password = userRegisterReqDTO.getPassword();
        String mail = userRegisterReqDTO.getMail();
        String phone = userRegisterReqDTO.getPhone();
        if (!ObjectUtil.isAllNotEmpty(username, password)) {
            log.info(String.format("username(%s) password(%s) 不能为空", username, password));
            throw new ClientException("参数错误");
        }
        if (ObjectUtil.isAllEmpty(mail, phone)) {
            log.info(String.format("mail(%s) phone(%s) 不能全为空", username, password));
            throw new ClientException("参数错误");
        }

        if (ObjectUtil.isNotEmpty(UserContext.getUserId())) {
            throw new ClientException("账号已登录");
        }

        if (hasUsername(userRegisterReqDTO.getUsername())) {
            throw new ClientException("用户名已存在");
        }
        RLock lock = redissonClient.getLock(String.format(LOCK_USER_REGISTER_KEY, userRegisterReqDTO.getUsername()));
        if (!lock.tryLock()) {
            throw new ClientException("用户名已存在");
        }
        try {
            //todo redis验证码登录扩展
            UserDO user = BeanUtil.copyProperties(userRegisterReqDTO, UserDO.class);
            long id = redissonClient.getIdGenerator(USER_ID_GENERATOR_KEY).nextId();
            user.setId(id);
            boolean succeed = save(user);
            if (!succeed) {
                throw new ServiceException("用户注册失败");
            }

            groupService.saveGroup(id, new GroupInsertReqDTO("默认分组"));
            RBloomFilter<Object> usernameBloomFilter = bloomFilterUtils.create(USERNAME_BLOOM_KEY);
            usernameBloomFilter.add(userRegisterReqDTO.getUsername());
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void update(UserUpdateReqDTO userUpdateReqDTO) {
        UserDO user = BeanUtil.copyProperties(userUpdateReqDTO, UserDO.class);
        user.setId(UserContext.getUserId());
        user.setDelFlag(UserDO.DEL_FLAG_FAIL);
        boolean succeed = updateById(user);
        if (!succeed) {
            throw new ServiceException("用户更新失败");
        }
    }

    @Override
    public UserInfoDTO login(String username, String password) {
        if (!ObjectUtil.isAllNotEmpty(username, password)) {
            log.info(String.format("username(%s) password(%s) 不能为空", username, password));
            throw new ClientException("参数错误");
        }

        UserDO user = lambdaQuery()
                .eq(UserDO::getUsername, username)
                .eq(UserDO::getPassword, password)
                .eq(UserDO::getDelFlag, UserDO.DEL_FLAG_FAIL)
                .one();
        if (user == null) {
            throw new ClientException("用户名或密码错误");
        }
        return new UserInfoDTO(user.getId(), username, user.getGroupName(), user.getGroupLevel());
    }

    @Override
    public Boolean checkLogin() {
        return ObjectUtil.isNotEmpty(UserContext.getUserId());
    }
}
